/* TEAM AWESOMES
 * -Kylan
 * -Leonardo
 * -Anthony
 *
 * relrecv receives a file from the relsend program
 */

#include "relrecv.h"

//////////////DECLARE GLOBAL VARS//////////////

int debug = true;
int sock; // send and receive socket
int port; // receiver port number
unsigned long fileSize = 0;
char fileName[22];
unsigned short seqNum;
unsigned long filePosition;
// relsend IP address.
char relsendAddress[16];
// relsend port number.
unsigned short relsendPort; 

//////////////DECLARE DEFINITIONS//////////////

int main(int argc, char**argv) {
    parseCommandLine(argc, argv);
    createSocket();
    receivePackets();
}

/**
 * Processes received messages (data, syn, and fin messages).
 *
 */
void receivePackets() {
  
	unsigned short iseqn = 1000;
	
	int addr_len;
  struct sockaddr_in client_addr;
	addr_len = sizeof (struct sockaddr);
	
	
	int bytesRead;
  unsigned char recvData[BUFSIZE];

	//Sockaddr pointer to store relsend's address and port.
  struct sockaddr relsendSap;

  while(1) {
    
		memset(recvData, 0, BUFSIZE);
   
		//bytesRead = receiveUDP(sock, recvData, sizeof(recvData), &relsendSap);
		bytesRead = recvfrom(sock, recvData, BUFSIZE, 0, (struct sockaddr *) &client_addr, &addr_len);
		
		
		strcpy(relsendAddress,(char *)inet_ntoa(client_addr.sin_addr));
		relsendPort = ntohs(client_addr.sin_port);
		// Struct to store relsend's address and port number
		//struct addressPort relsendInfo;

		// Enters information into addressPort struct that stores relsend's address/port
		//getAddressPort(&relsendSap, &relsendInfo);

		if (debug) {
			printf("receivePackets function: bytesRead %d\n", bytesRead);
			printf("Receiving data from %s : %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
		}
		
    // A control packet
    if(recvData[0] == 204) {
		
			if(recvData[1] == 170) {
				if (debug) {	
					printf("It's a SYN packet.\n\n\n");
				}
				
				short * tmpNum;
				void * ptr = (void *) recvData+2;
				tmpNum = (short *) ptr;
				seqNum = htons(* tmpNum);
				strcpy(fileName, recvData+4); 
				
				unsigned long * temp = (unsigned long * ) fileSize;
				
				seqNum = handleSynMessage(recvData, fileName, iseqn, relsendAddress, relsendPort, temp);
				
				if (debug) {
					printf("we got past relrecv handleSynMessage\n");
				}

				sendACK(fileName, seqNum, relsendAddress, relsendPort);
				
			}
			// FIN packet received.
			else if(recvData[1] == 238) {
				if (debug) {
					printf("It's a FIN packet.\n\n\n");
				}
				sendACK(fileName, seqNum, relsendAddress, relsendPort);
				exit(0);
			}
    }
    // Data packet received.
    else { //if(recvData[0] == 221)
      printf("It's a data packet.\n\n\n");
      //receiveFile(recvData, bytesRead);
    }
  }
}


void sendACK(char * filename, short seqNum, char * address, unsigned short port) {
	struct sockaddr_in server_addr;
  struct hostent *recvr;
	char ackBuffer[25];
    
	recvr = gethostbyname(address);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(port);
  server_addr.sin_addr = *((struct in_addr *) recvr->h_addr);
  bzero(&(server_addr.sin_zero), 8);

	createAckMessage(ackBuffer, fileName, (seqNum+1)%65535);
	sendto(sock, ackBuffer, strlen(ackBuffer), 0, (struct sockaddr *) &server_addr, sizeof (struct sockaddr));
}


void receiveFile(char * recvData, int bytesRead) {

    printf("\nWaiting for data on port %d\n", port);

	//Point i to the beginning of the data
	int i;
	for(i = 0; i < bytesRead; i++) {
		if(recvData[i] == '\0') {
			i += 5;
			break;
		}
	}
   
   
    //append r to fileName
    char fileName[20];
    char newFilename[22];
    newFilename[0] = 'r';
    strcpy(fileName, recvData+3); 
    int k;
    for(k = 0; k < strlen(fileName); k++) {
    	newFilename[k+1] = fileName[k];
    }

		newFilename[k+1] = '\0';
	
    FILE *fp;
    fp=fopen(newFilename, "ab");
    
    //start fputting chars from index i
    int x;
    for(x = i; x < bytesRead; x++) {
      fputc(recvData[x], fp);
    }
    
    fclose(fp);
    
}



void parseCommandLine(int argc, char**argv) {

    // Validate number of arguments
    if (argc != 2) {
        printf("Invalid arguments, use format: ./relrecv <port>\n");
        exit(1);
    }

    // Validate port number
    int tempPort;
    if(tempPort = atoi(argv[1])) {
        //Check port range
        if(tempPort < 1025 || tempPort > 65535) {
            printf("Invalid port, port must be in range 1025-65535.\n");
            exit(1);
        }
        else {
            port = tempPort;
            if(debug) { printf("Port: %d\n", port); }
        }
    }
    else { // check if atoi passed
        printf("Invalid port: port must be a number.\n");
        exit(1);
    }
    
}

void createSocket() {

    struct sockaddr_in server_addr;

    // Generate the socket
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Socket");
        exit(1);
    }

    // Set up struct to receive data from our port and address
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(server_addr.sin_zero), 8);

    // Bind the struct to our socket
    if (bind(sock, (struct sockaddr *) &server_addr,
            sizeof (struct sockaddr)) == -1) {
        perror("Bind");
        exit(1);
    }

}

/** Checks if the file exists in the directory 
 *
 * @param filename The filename to check.
 * @return True if file exists, otherwise false.
 */
int exists(const char * filename) {
  FILE *file;
  
  if (file = fopen(filename, "r")) {
		fclose(file);
    return true;
  }  
	return false;
}
